import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class Main {
    private static Logger l;

    public static void main1(String[] args) throws Exception {
        String line = "20220505 10:33:53 泰林转债证券买入";
        Pattern p = Pattern.compile("(\\d{8} \\d{0,2}:\\d{2}:\\d{2})", Pattern.MULTILINE|Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(line);
        if(m.find()) {
            System.out.println("found");
            return;
        }
        System.out.println("notfound");
    }

    static int cntChar(String line, char find) {
        int cnt = 0;
        for (char ch :line.toCharArray()){
            if(ch == find) {
                cnt++;
            }
        }
        return cnt;
    }

    public static void main(String[] args) throws Exception {
        List<Order> list = new ArrayList<Order>();
        InputStream inputStream = Main.class.getResourceAsStream("ss.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
        String line = null;
        int ind = 0;
        while ((line = reader.readLine()) != null) {
            ind++;
            boolean match = line.indexOf("证券买入") > 0 || line.indexOf("证券卖出") > 0;
            if(!match){
                continue;
            }


            if(cntChar(line, '转') != 1) {
                throw new RuntimeException("line " + ind + " nokeyword 转 :" + line);
            }
            //两个空格替换成一个空格
            line = line.replaceAll("  ", " ");
            //20220505 10:33:53
            Pattern p = Pattern.compile("(\\d{8} \\d{0,2}:\\d{2}:\\d{2})", Pattern.MULTILINE|Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
            Matcher m = p.matcher(line);
            m.find();
//            System.out.println(ind+":"+line);

            String daytime = m.group(1);
            int spaceInd = daytime.length();
            if(line.charAt(spaceInd) != ' ') {
                String line2 = line.substring(0, spaceInd) +' ' + line.substring(spaceInd);
                //l.info(line + " format to " + line2)
                line = line2;
            }
            int ind0 = line.indexOf("证券买入");
            int ind1 = line.indexOf("证券卖出");
            if(ind0 > -1 && line.charAt(ind0 - 1) != ' ') {
                line = line.substring(0, ind0) + ' ' + line.substring(ind0);
            }
            if(ind1 > -1 && line.charAt(ind1 - 1) != ' ') {
                line = line.substring(0, ind1) + ' ' + line.substring(ind1);
            }
            //System.out.println(ind+":   "+line);

            //成交日期成交时间证券名称操作 成交数量 成交均价成交金额 余额
            int idx = 0;
            String[] items = line.split(" ");
            String day = items[idx++];
            String time = items[idx++];
            String name = items[idx++];
            String act = items[idx++];
            int vol = 0;
            Double price = null;
            Double amount = null;
            int remain;
            String volStr = null; String priceStr = null;
            String amountStr = null; String remainStr = null;
            if(vol == 0) {
                volStr = items[idx++];
                vol = Integer.valueOf(volStr);
            }

            if(line.startsWith("20220509 10:56:03")) {
                System.out.println();
            }

            if(price == null) {
                priceStr = items[idx++];
                if(cntChar(priceStr, '.') > 1) {

                    int idx2 = priceStr.indexOf(".");
                    price = Double.valueOf(priceStr.substring(0, idx2+4));
                    amount = Double.valueOf(priceStr.substring(idx2+4));
                    BigDecimal calAmount = new BigDecimal(price).multiply(new BigDecimal(Math.abs(vol))).divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP);
                    if(!calAmount.equals(new BigDecimal(amount).divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP))) {
                        price = Double.valueOf(priceStr.substring(0, idx2+3));
                        amount = Double.valueOf(priceStr.substring(idx2+3));
                    }
                    calAmount = new BigDecimal(price).multiply(new BigDecimal(Math.abs(vol))).divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP);
                    if(!calAmount.equals(new BigDecimal(amount).divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP))) {
                        throw new RuntimeException("line " + ind + " :" + day+" "+ time+" "+ name+" "+ act+" "+ vol+" "+ price+" "+amount);
                    }
                } else {
                    price = Double.valueOf(priceStr);
                }
            }

            if(amount == null) {
                amountStr = items[idx++];
                amount = Double.valueOf(amountStr);
            }

            if(idx < items.length) {
                remain = Integer.valueOf(items[idx]);
            } else {
                remain = 0;
            }
            if(8 < items.length) {
                System.err.println(ind + ": long data = " + line);
                return;
            }

            if(act.indexOf("买入") > -1 && vol <= 0) {
                throw new RuntimeException(ind + ": bs vol error = " + line);
            }

            if(act.indexOf("卖出") > -1 && vol >= 0) {
                throw new RuntimeException(ind + ": bs vol error = " + line);
            }

            if(act.indexOf("买入") > -1 && remain <= 0) {
                throw new RuntimeException(ind + ": bs remain error = " + line);
            }
            BigDecimal calAmount = new BigDecimal(price).multiply(new BigDecimal(Math.abs(vol))).divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP);
            if(!calAmount.equals(new BigDecimal(amount).divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP))) {
                System.err.println("line " + ind + " :" + day+" "+ time+" "+ name+" "+ act+" "+ vol+" "+ price+" "+amount);
            }

            Order order = new Order();
            order.setAmount(amount);
            order.setBs(act);
            order.setDay(day);
            order.setName(name);
            order.setTime(time);
            order.setPrice(price);
            order.setVol(vol);
            order.setRemain(remain);
            order.setLine(line);
            list.add(order);
        }
        Map<String, List<Order>> map = list.stream().collect(Collectors.groupingBy(it->{
            return it.getDay() + " " + it.getTime() + " " + it.getName() + " " + it.getBs();
        }));
        StringBuilder sd = new StringBuilder();
        for (List<Order> orders : map.values()) {
            long cnt = orders.stream().distinct().count();
            if(cnt > 1) {
                sd.append("================================================\r\n");
                sd.append(orders.stream().map(Order::toString).collect(Collectors.joining("\r\n")));
            }
        }
        System.err.println(sd.toString());

        list = list.stream().distinct().collect(Collectors.toList());
        System.out.println("uniq list size = " + list.size());

        list = list.stream().sorted((it1, it2)->{
            if(!it1.getDay().equals(it2)) {
                return Integer.valueOf(it1.getDay()) - Integer.valueOf(it2.getDay());
            }
            return Integer.valueOf(it1.getTime().replaceAll(":", ""))
                    - Integer.valueOf(it2.getTime().replaceAll(":", ""));
        }).collect(Collectors.toList());
        list.stream().filter(it->{
            return it.getDay().equals("20220506")&&
                    (it.getTime().equals("14:42:18") || it.getTime().equals("9:25:00"));
        }).collect(Collectors.toList());

        System.out.println(list);
        Collections.sort(list, (it1, it2)->{
            if(!it1.getDay().equals(it2.getDay())) {
                return Integer.valueOf(it1.getDay()) - Integer.valueOf(it2.getDay());
            }
            return Integer.valueOf(it1.getTime().replaceAll(":", ""))
                    - Integer.valueOf(it2.getTime().replaceAll(":", ""));
        });

        List findList = list.stream().filter(it->{
            return it.getDay().equals("20220506")
                    && it.getTime().equals("10:31:54");
        }).collect(Collectors.toList());

        Map<String, Integer> cntMap = new HashMap<>();
        for (Order order : list) {
            System.out.println(order.getLine());
            int cnt = cntMap.getOrDefault(order.getName(), 0);
            cnt += order.getVol();
            if(cnt != order.getRemain()) {
                System.err.println("expect remain " + cnt + " but found " + order.getRemain());
                return;
            }
            cntMap.put(order.getName(), cnt);
        }
        double allProfit = 0;
        Map<String, LinkedList<Order>> profitList = new HashMap<>();
        for (Order order : list) {
            if(order.getBs() .equals("证券买入")) {
                LinkedList blist = profitList.getOrDefault(order.getName(), new LinkedList<>());
                blist.add(order);
                profitList.put(order.getName(), blist);
                continue;
            }
            if(order.getBs().equals("证券卖出")) {
                int vol = Math.abs(order.getVol());
                double price = order.getPrice();
                double calAmount = Math.abs(vol)*price;
                double amount = order.getAmount();
                LinkedList<Order> borderList = profitList.get(order.getName());
                while(vol > 0) {
                    Order buyOrder = borderList.getFirst();
                    if(vol <= buyOrder.getVol()) {
                        buyOrder.setVol(buyOrder.getVol() - vol);
                        double profit = vol * price - vol * buyOrder.getPrice();
                        allProfit += profit;
                        order.setBnote(order.getBnote() + " 买入：" + buyOrder.getDay() +" " + buyOrder.getTime() + " " + buyOrder.getPrice() + " " + vol + " | ");
                        vol = 0;
                        order.setProfit(order.getProfit() + profit);
                    } else {
                        vol -= buyOrder.getVol();
                        double profit = buyOrder.getVol() * (price - buyOrder.getPrice());
                        allProfit += profit;
                        order.setBnote(order.getBnote() + " 买入：" + buyOrder.getDay() +" " + buyOrder.getTime() + " " + buyOrder.getPrice() + " " + buyOrder.getVol() + " | ");
                        buyOrder.setVol(0);
                        order.setProfit(order.getProfit() + profit);
                    }
                    order.setHoldTime(Math.max(order.getHoldTime(), getTimePeriod(buyOrder.getDay(), buyOrder.getTime(), order.getDay(), order.getTime())));
                    if(buyOrder.getVol() == 0) {
                        borderList.removeFirst();
                    }
                }
                order.setProfit(Math.round(order.getProfit()));
                double rate = new BigDecimal(((order.getProfit() * 100)/order.getAmount())).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                System.out.println(order.getName() + " " + order.getBnote() + " 卖出：" + order.getDay() +" " + order.getTime() + " " + order.getPrice() + " " + Math.abs(order.getVol()) + " 利润： " + rate + "%（"+order.getProfit()+"）| 持股：" + timeMills2Str(order.getHoldTime()));
                continue;
            }
            System.err.println("error bs");
            return;
        }
        for (Order order : list) {
            String sql = "insert into stk_jgd(day, time, name, bs, vol, price, amount) values('%s', '%s', '%s', '%s', '%s', '%s', '%s')";
            String insertSQL = String.format(sql, order.getDay(), order.getTime(), order.getName(), order.getBs(), order.getVol(), order.getPrice(), order.getAmount());
            System.out.println(insertSQL);
        }
        System.out.println("end, allProfit=" + allProfit);

    }

    public static long getTimePeriod(String startDay, String startTime, String endDay, String endTime) throws Exception {
        if(startTime.length() == "9:25:00".length()) {
            startTime = "0" + startTime;
        }
        if(endTime.length() == "9:25:00".length()) {
            endTime = "0" + endTime;
        }
        Date start = new SimpleDateFormat("yyyyMMdd HH:mm:ss").parse(startDay +" " + startTime);
        Date end = new SimpleDateFormat("yyyyMMdd HH:mm:ss").parse(endDay +" " + endTime);
        return end.getTime() - start.getTime();
    }

    public static String timeMills2Str(long time) {
        int h = (int)time/(60*60*1000);
        time -= h* 60*60*1000;
        int m = (int)time/(60*1000);
        time -= m * 60*1000;
        int s = (int)time/1000;
        return h+"时"+m+"分"+s+"秒";
    }
}
